package com.aiapphub.SystemCode.controller;

import com.aiapphub.BaseCode.common.ResponseResult;
import com.aiapphub.BaseCode.entity.SsoUser;
import com.aiapphub.SystemCode.dto.AiChatRequest;
import com.aiapphub.SystemCode.dto.DifyFileInfo;
import com.aiapphub.SystemCode.dto.WorkflowRunRequest;
import com.aiapphub.SystemCode.service.WorkflowStreamResponseHandler;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.aiapphub.SystemCode.service.DifyFileService;
import com.aiapphub.SystemCode.service.DifyClientService;
import com.aiapphub.SystemCode.service.DifyConversationService;
import com.aiapphub.SystemCode.service.DifyMessageService;
import com.aiapphub.SystemCode.service.StreamResponseHandler;
import com.aiapphub.SystemCode.service.UserService;
import com.aiapphub.SystemCode.service.AppMappingService;
import com.aiapphub.SystemCode.entity.AppMapping;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * AI对话控制器 - 统一管理AI聊天和Dify API功能
 */
@Slf4j
@RestController
@RequestMapping("/api/ai/chat")
@Api(tags = "AI对话管理")
public class AiChatController {
    
    @Resource
    private DifyClientService difyClientService;
    
    @Value("${dify.api.key:}")
    private String difyApiKey;
    
    @Value("${dify.api.url:}")
    private String DIFY_API_BASE_URL;
    
    @Resource
    private DifyFileService aiFileService;
    
    @Resource
    private UserService userService;
    
    @Resource
    private DifyConversationService difyConversationService;
    
    @Resource
    private DifyMessageService difyMessageService;

    @Resource
    private AppMappingService appMappingService;

    /**
     * 验证字符串是否为有效的UUID格式
     * @param uuid 待验证的字符串
     * @return 是否为有效的UUID格式
     */
    private boolean isValidUUID(String uuid) {
        if (uuid == null || uuid.trim().isEmpty()) {
            return false;
        }
        String uuidRegex = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$";
        return uuid.toLowerCase().matches(uuidRegex);
    }
    
    /**
     * 根据appName获取API基础URL
     * @param appName App名称
     * @return API基础URL
     */
    private String getApiBaseUrl(String appName) {
        if (appName != null && "treasury_app".equals(appName.trim())) {
            return "http://11.72.49.4/v1";
        }
        return DIFY_API_BASE_URL;
    }
    
    /**
     * 发送聊天消息（流式响应）
     */
    @PostMapping(value = "/send/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ApiOperation("发送聊天消息（流式响应）")
    public SseEmitter sendMessageStream(@RequestBody AiChatRequest request) {
        // 设置SseEmitter超时时间为1小时（3600000毫秒），与异步处理配置一致
        // 防止资源泄露并确保长时间流式连接的稳定性
        final SseEmitter emitter = new SseEmitter(3600000L);
         log.info("收到消息==============================:" + request.getMessage());
        try {
            // 验证会话ID格式（如果提供）
            String conversationId = request.getConversationId();
            if (conversationId != null && !conversationId.trim().isEmpty()) {
                if (!isValidUUID(conversationId)) {
                    emitter.send("{\"error\":\"会话ID:'"+conversationId+"'格式不正确，必须是UUID格式\"}");
                    emitter.complete();
                    return emitter;
                }
            }
            
            // 发送会话信息（如果有会话ID）
            if (conversationId != null && !conversationId.trim().isEmpty()) {
                emitter.send("{\"conversationId\":\"" + conversationId + "\"}");
            }
            
            // 调用Dify流式API
            String difyConversationId = conversationId;
            
            StringBuilder fullResponse = new StringBuilder();
            // 使用用户服务获取用户ID，确保一致性
            String userId = userService.getCurrentUserId();
            log.info("使用用户服务获取的用户ID:========================= " + userId);
            
            // 处理文件信息
            List<DifyFileInfo> difyFiles = request.getFiles();
            if (difyFiles != null && !difyFiles.isEmpty()) {
                 log.info("发送消息包含文件: " + difyFiles.size() + " 个");
                for (DifyFileInfo file : difyFiles) {
                     log.info("文件信息: type=" + file.getType() + 
                        ", transfer_method=" + file.getTransfer_method() + 
                        ", upload_file_id=" + file.getUpload_file_id());
                }
            }
            SsoUser user = userService.getCurrentUser();
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (request.getAppName() != null && !request.getAppName().trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(request.getAppName().trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("通过App名称 '{}' 查询到 API Key", request.getAppName());
                } else {
                    emitter.send("{\"error\":\"App名称 '" + request.getAppName() + "' 不存在或已禁用\"}");
                    emitter.complete();
                    return emitter;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String appName = request.getAppName();
            String apiBaseUrl = getApiBaseUrl(appName);
            
            // 构建JSON请求参数
            Map<String, Object> requestParams = new HashMap<>();
            requestParams.put("query", request.getMessage());
            requestParams.put("user", userId);
            requestParams.put("conversation_id", difyConversationId);
            requestParams.put("difyApiKey", actualApiKey);
            requestParams.put("requestUrl", apiBaseUrl + "/chat-messages");
            
            // 合并前端传入的 inputs 和系统用户信息
            Map<String, Object> inputs = new HashMap<>();
            
            // 1. 首先添加系统用户信息
            inputs.put("orgNamePath", user.getOrgNamePath());
            inputs.put("orgName", user.getOrgName());
            inputs.put("sex", user.getSex());
            inputs.put("userName", user.getUserName());
            inputs.put("telephone", user.getTelephone());
            inputs.put("email", user.getEmail());
            inputs.put("appName", user.getAppName());
            inputs.put("appSn", user.getAppSn());
            inputs.put("acctStatus", user.getAcctStatus());
            inputs.put("loginName", user.getLoginName());
            inputs.put("nickName", user.getNickName());
            inputs.put("avatar", user.getAvatar());
            inputs.put("delFlag", user.getDelFlag());
            
            // 2. 然后合并前端传入的 inputs（包含文件变量等用户自定义参数）
            if (request.getInputs() != null && !request.getInputs().isEmpty()) {
                inputs.putAll(request.getInputs());
                log.info("合并前端 inputs: {}", request.getInputs());
            }
            
            requestParams.put("inputs", inputs);
            if (difyFiles != null && !difyFiles.isEmpty()) {
                requestParams.put("files", difyFiles);
            }
            
            String requestJson = JSON.toJSONString(requestParams);
            log.info("发送到DifyClientService的JSON参数: {}", requestJson);
            
            difyClientService.sendChatMessageStream(
                apiBaseUrl + "/chat-messages",
                actualApiKey,
                requestJson,
                new StreamResponseHandler() {
                    @Override
                    public void onMessage(String message) {
                        try {
                            //System.out.println("message=============" + message);
                            fullResponse.append(message);
                            emitter.send("{\"content\":\"" + 
                                message.replace("\"", "\\\"").replace("\n", "\\n") + "\"}");
                        } catch (Exception e) {
                            log.error("发送流式消息异常", e);
                        }
                    }
                    
                    @Override
                    public void onError(Exception error) {
                        try {
                            emitter.send("{\"error\":\"" + 
                                error.getMessage().replace("\"", "\\\"") + "\"}");
                            emitter.completeWithError(error);
                        } catch (Exception e) {
                            log.error("发送错误消息异常", e);
                        }
                    }
                    
                    @Override
                    public void onConversationId(String newDifyConversationId) {
                        try {
                            // 发送会话ID到前端
                            emitter.send("{\"type\":\"conversation\",\"conversationId\":\"" + newDifyConversationId + "\"}");
                        } catch (Exception e) {
                            log.error("发送会话ID异常", e);
                        }
                    }
                    
                    @Override
                    public void onComplete() {
                        try {
                            emitter.send("[DONE]");
                            emitter.complete();
                        } catch (Exception e) {
                            log.error("完成流式响应异常", e);
                        }
                    }
                    
                    @Override
                    public void onComplete(JSONObject finalData) {
                        try {
                            log.info("发送完整数据到前端: {}", finalData.toString());
                            // 发送完整的最终数据（包括 files、metadata 等）
                            // Spring SseEmitter 会自动添加 data: 前缀，直接发送 JSON 字符串即可
                            emitter.send(finalData.toString());
                            emitter.send("[DONE]");
                            emitter.complete();
                        } catch (Exception e) {
                            log.error("完成流式响应异常", e);
                        }
                    }
                });
        } catch (Exception e) {
            log.error("流式响应异常", e);
            try {
                emitter.send("data: {\\\"error\\\":\\\"服务器内部错误\\\"}\\n\\n");
            } catch (Exception ex) {
                log.error("发送错误响应异常", ex);
            } finally {
                emitter.completeWithError(e);
            }
        }
        
        return emitter;
    }
    
    /**
     * 获取会话列表（使用Dify API）
     */
    @GetMapping("/conversations")
    @ApiOperation("获取会话列表")
    public Map<String, Object> getConversations(
            @RequestParam String userId,
            @RequestParam(defaultValue = "20") Integer limit,
            @RequestParam(required = false) String appName) {
        try {
            // 使用用户服务获取用户ID，确保一致性
            String actualUserId = userService.getCurrentUserId();
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("获取会话列表 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            List<Map<String, Object>> conversations = difyConversationService.getConversationsByUserId(actualUserId, limit, actualApiKey, apiBaseUrl);
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("data", conversations);
            result.put("total", conversations.size());
            return result;
        } catch (Exception e) {
            log.error("获取会话列表失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取会话消息历史（使用Dify API）
     */
    @GetMapping("/conversations/{conversationId}/messages")
    @ApiOperation("获取会话消息历史")
    public Map<String, Object> getConversationMessages(
            @PathVariable String conversationId,
            @RequestParam String userId,
            @RequestParam(defaultValue = "20") Integer limit,
            @RequestParam(required = false) String appName) {
        try {
            String actualUserId = userService.getCurrentUserId();
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("获取会话消息历史 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            List<Map<String, Object>> messages = difyMessageService.getMessagesByConversationId(conversationId, actualUserId, limit, actualApiKey, apiBaseUrl);
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("data", messages);
            result.put("total", messages.size());
            return result;
        } catch (Exception e) {
            log.error("获取会话消息历史失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 归档会话（使用Dify API）
     */
    @PostMapping("/conversations/{conversationId}/archive")
    @ApiOperation("归档会话")
    public Map<String, Object> archiveConversation(
            @PathVariable String conversationId,
            @RequestParam String userId) {
        try {
            String actualUserId = userService.getCurrentUserId();
            boolean success = difyConversationService.archiveConversation(conversationId, actualUserId);
            Map<String, Object> result = new HashMap<>();
            result.put("success", success);
            if (success) {
                result.put("message", "会话归档成功");
            } else {
                result.put("message", "会话归档失败");
            }
            return result;
        } catch (Exception e) {
            log.error("归档会话失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 上传文件到Dify API
     */
    @PostMapping("/upload")
    @ApiOperation("上传文件到Dify API")
    public ResponseResult<com.aiapphub.SystemCode.entity.AiFile> uploadFile(@RequestParam("file") MultipartFile file,
                                           @RequestParam String userId,
                                           @RequestParam(required = false) String appName) {
        try {
            if (file.isEmpty()) {
                System.out.println("文件不能为空====================================");
                return ResponseResult.errorResult(400, "文件不能为空");
            }
            System.out.println("userId===================================="+userId);
            // 使用用户服务获取用户ID
            String actualUserId = userService.getCurrentUserId();
            System.out.println("actualUserId===================================="+actualUserId);
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            log.info("appName===================================="+appName);
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("actualApiKey===================================="+actualApiKey);
                    
                    log.info("上传文件 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    return ResponseResult.errorResult(400, "App名称 '" + appName + "' 不存在或已禁用");
                }
            }
            
            // 检查文件大小（限制为10MB）
            if (file.getSize() > 10 * 1024 * 1024) {
                return ResponseResult.errorResult(400, "文件大小不能超过10MB");
            }
            
            // 检查文件类型（支持图片和文档格式）
            String contentType = file.getContentType();
            if (contentType == null || (!contentType.startsWith("image/") && 
                !contentType.equals("application/pdf") &&
                !contentType.equals("application/msword") &&
                !contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document") &&
                !contentType.equals("application/vnd.ms-excel") &&
                !contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))) {
                return ResponseResult.errorResult(400, "仅支持图片格式 (png, jpeg, jpg, webp, gif) 和文档格式 (pdf, doc, docx, xls, xlsx)");
            }
            
            // 上传到Dify API（传递 API Key）
            com.aiapphub.SystemCode.entity.AiFile uploadedFile = aiFileService.uploadFileToDify(file, actualUserId, actualApiKey);
            System.out.println("uploadedFile===================================="+uploadedFile.getDifyResponse());
            return ResponseResult.okResult(uploadedFile);
            
        } catch (Exception e) {
            log.error("上传文件到Dify API异常", e);
            return ResponseResult.errorResult(500, "上传文件失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取用户文件列表（已弃用）
     * @deprecated 已弃用，文件信息不再存储在本地数据库
     */
    @GetMapping("/files")
    @ApiOperation("获取用户文件列表（已弃用）")
    @Deprecated
    public ResponseResult<List<com.aiapphub.SystemCode.entity.AiFile>> getUserFiles(@RequestParam String userId) {
        return ResponseResult.errorResult(501, "此接口已弃用，文件信息不再存储在本地数据库");
    }
    
    /**
     * 删除文件（已弃用）
     * @deprecated 已弃用，文件信息不再存储在本地数据库
     */
    @DeleteMapping("/files/{fileId}")
    @ApiOperation("删除文件（已弃用）")
    @Deprecated
    public ResponseResult<Void> deleteFile(@PathVariable Long fileId) {
        return ResponseResult.errorResult(501, "此接口已弃用，文件信息不再存储在本地数据库");
    }
    
    // ==================== Dify API 功能 ====================
    
    /**
     * 获取Dify会话详情
     */
    @GetMapping("/dify/conversations/{conversationId}")
    @ApiOperation("获取Dify会话详情")
    public Map<String, Object> getDifyConversation(
            @PathVariable String conversationId,
            @RequestParam String userId) {
        try {
            String actualUserId = userService.getCurrentUserId();
            Map<String, Object> conversation = difyConversationService.getConversationById(conversationId, actualUserId);
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("data", conversation);
            return result;
        } catch (Exception e) {
            log.error("获取Dify会话详情失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 删除Dify会话
     */
    @DeleteMapping("/dify/conversations/{conversationId}")
    @ApiOperation("删除Dify会话")
    public Map<String, Object> deleteDifyConversation(
            @PathVariable String conversationId,
            @RequestParam String userId,
            @RequestParam(required = false) String appName) {
        try {
            String actualUserId = userService.getCurrentUserId();
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("删除会话 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            boolean success = difyConversationService.deleteConversation(conversationId, actualUserId, actualApiKey);
            Map<String, Object> result = new HashMap<>();
            result.put("success", success);
            if (success) {
                result.put("message", "会话删除成功");
            } else {
                result.put("message", "会话删除失败");
            }
            return result;
        } catch (Exception e) {
            log.error("删除Dify会话失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 重命名Dify会话
     */
    @PostMapping("/dify/conversations/{conversationId}/name")
    @ApiOperation("重命名Dify会话")
    public Map<String, Object> renameDifyConversation(
            @PathVariable String conversationId,
            @RequestParam String userId,
            @RequestParam String name,
            @RequestParam(defaultValue = "false") boolean autoGenerate,
            @RequestParam(required = false) String appName) {
        try {
            String actualUserId = userService.getCurrentUserId();
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("重命名会话 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            boolean success = difyConversationService.renameConversation(conversationId, name, actualUserId, autoGenerate, actualApiKey);
            Map<String, Object> result = new HashMap<>();
            result.put("success", success);
            if (success) {
                result.put("message", "会话重命名成功");
            } else {
                result.put("message", "会话重命名失败");
            }
            return result;
        } catch (Exception e) {
            log.error("重命名Dify会话失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取Dify归档会话列表
     */
    @GetMapping("/dify/conversations/archived")
    @ApiOperation("获取Dify归档会话列表")
    public Map<String, Object> getDifyArchivedConversations(
            @RequestParam String userId,
            @RequestParam(defaultValue = "20") Integer limit) {
        try {
            String actualUserId = userService.getCurrentUserId();
            List<Map<String, Object>> conversations = difyConversationService.getArchivedConversations(actualUserId, limit);
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("data", conversations);
            result.put("total", conversations.size());
            return result;
        } catch (Exception e) {
            log.error("获取Dify归档会话列表失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 恢复Dify会话
     */
    @PostMapping("/dify/conversations/{conversationId}/unarchive")
    @ApiOperation("恢复Dify会话")
    public Map<String, Object> unarchiveDifyConversation(
            @PathVariable String conversationId,
            @RequestParam String userId) {
        try {
            String actualUserId = userService.getCurrentUserId();
            boolean success = difyConversationService.unarchiveConversation(conversationId, actualUserId);
            Map<String, Object> result = new HashMap<>();
            result.put("success", success);
            if (success) {
                result.put("message", "会话恢复成功");
            } else {
                result.put("message", "会话恢复失败");
            }
            return result;
        } catch (Exception e) {
            log.error("恢复Dify会话失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取Dify单个消息
     */
    @GetMapping("/dify/messages/{messageId}")
    @ApiOperation("获取Dify单个消息")
    public Map<String, Object> getDifyMessage(
            @PathVariable String messageId,
            @RequestParam String userId) {
        try {
            String actualUserId = userService.getCurrentUserId();
            Map<String, Object> message = difyMessageService.getMessageById(messageId, actualUserId);
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("data", message);
            return result;
        } catch (Exception e) {
            log.error("获取Dify消息失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 删除Dify消息
     */
    @DeleteMapping("/dify/messages/{messageId}")
    @ApiOperation("删除Dify消息")
    public Map<String, Object> deleteDifyMessage(
            @PathVariable String messageId,
            @RequestParam String userId) {
        try {
            String actualUserId = userService.getCurrentUserId();
            boolean success = difyMessageService.deleteMessage(messageId, actualUserId);
            Map<String, Object> result = new HashMap<>();
            result.put("success", success);
            if (success) {
                result.put("message", "消息删除成功");
            } else {
                result.put("message", "消息删除失败");
            }
            return result;
        } catch (Exception e) {
            log.error("删除Dify消息失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 添加Dify消息反馈
     */
    @PostMapping("/dify/messages/{messageId}/feedbacks")
    @ApiOperation("添加Dify消息反馈")
    public Map<String, Object> addDifyMessageFeedback(
            @PathVariable String messageId,
            @RequestParam String userId,
            @RequestParam String rating,
            @RequestParam(required = false) String comment) {
        try {
            String actualUserId = userService.getCurrentUserId();
            boolean success = difyMessageService.addMessageFeedback(messageId, actualUserId, rating, comment);
            Map<String, Object> result = new HashMap<>();
            result.put("success", success);
            if (success) {
                result.put("message", "反馈添加成功");
            } else {
                result.put("message", "反馈添加失败");
            }
            return result;
        } catch (Exception e) {
            log.error("添加Dify消息反馈失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取Dify消息反馈
     */
    @GetMapping("/dify/messages/{messageId}/feedbacks")
    @ApiOperation("获取Dify消息反馈")
    public Map<String, Object> getDifyMessageFeedback(
            @PathVariable String messageId,
            @RequestParam String userId) {
        try {
            String actualUserId = userService.getCurrentUserId();
            Map<String, Object> feedback = difyMessageService.getMessageFeedback(messageId, actualUserId);
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("data", feedback);
            return result;
        } catch (Exception e) {
            log.error("获取Dify消息反馈失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 停止Dify消息生成
     */
    @PostMapping("/dify/chat-messages/{taskId}/stop")
    @ApiOperation("停止Dify消息生成")
    public Map<String, Object> stopDifyMessageGeneration(
            @PathVariable String taskId,
            @RequestParam String userId,
            @RequestParam(required = false) String appName) {
        try {
            String actualUserId = userService.getCurrentUserId();
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("停止消息生成 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            boolean success = difyMessageService.stopMessageGeneration(taskId, actualUserId, actualApiKey);
            Map<String, Object> result = new HashMap<>();
            result.put("success", success);
            if (success) {
                result.put("message", "消息生成已停止");
            } else {
                result.put("message", "停止消息生成失败");
            }
            return result;
        } catch (Exception e) {
            log.error("停止Dify消息生成失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取Dify消息建议
     */
    @GetMapping("/dify/messages/{messageId}/suggestions")
    @ApiOperation("获取Dify消息建议")
    public Map<String, Object> getDifyMessageSuggestions(
            @PathVariable String messageId,
            @RequestParam String userId,
            @RequestParam(required = false) String appName) {
        try {
            String actualUserId = userService.getCurrentUserId();
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("获取消息建议 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            List<String> suggestions = difyMessageService.getMessageSuggestions(messageId, actualUserId, actualApiKey);
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("data", suggestions);
            return result;
        } catch (Exception e) {
            log.error("获取Dify消息建议失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取Dify应用参数
     */
    @GetMapping("/dify/parameters")
    @ApiOperation("获取Dify应用参数")
    public Map<String, Object> getDifyAppParameters(
            @RequestParam(required = false) String appName) {
        try {
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("获取应用参数 - 通过App名称 '{}' 查询到 API Key", appName);
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            // 调用Dify API获取应用参数
            String url = apiBaseUrl + "/parameters";
            okhttp3.Request request = new okhttp3.Request.Builder()
                    .url(url)
                    .get()
                    .addHeader("Authorization", "Bearer " + actualApiKey)
                    .addHeader("Content-Type", "application/json")
                    .build();
            
            // 创建OkHttpClient，设置超时时间
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(20, java.util.concurrent.TimeUnit.SECONDS)
                    .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            try (okhttp3.Response response = client.newCall(request).execute()) {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    JSONObject jsonResponse = JSON.parseObject(responseBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", true);
                    result.put("data", jsonResponse);
                    return result;
                } else {
                    String errorBody = response.body() != null ? response.body().string() : "Unknown error";
                    log.error("获取应用参数失败，状态码: {}, 错误信息: {}", response.code(), errorBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "获取应用参数失败: " + errorBody);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("获取Dify应用参数失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    // ==================== Workflow API 功能 ====================
    
    /**
     * 执行 Workflow（流式响应）
     */
    @PostMapping(value = "/workflow/run", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ApiOperation("执行 Workflow（流式响应）")
    public SseEmitter runWorkflowStream(@RequestBody WorkflowRunRequest request) {
        final SseEmitter emitter = new SseEmitter(3600000L);
        log.info("收到 Workflow 执行请求");
        
        try {
            String userId = userService.getCurrentUserId();
            log.info("使用用户服务获取的用户ID: {}", userId);
            
            // 处理 App名称：如果提供了App名称，则通过App名称查询真实的 API Key
            String actualApiKey = difyApiKey;
            if (request.getAppName() != null && !request.getAppName().trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(request.getAppName().trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                    log.info("通过App名称 '{}' 查询到 API Key", request.getAppName());
                } else {
                    emitter.send("{\"error\":\"App名称 '" + request.getAppName() + "' 不存在或已禁用\"}");
                    emitter.complete();
                    return emitter;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String appName = request.getAppName();
            String apiBaseUrl = getApiBaseUrl(appName);
            
            // 构建请求参数
            Map<String, Object> requestParams = new HashMap<>();
            // 直接使用前端传递的 inputs（文件信息可能已经在 inputs 中作为工作流输入变量）
            Map<String, Object> inputs = request.getInputs() != null ? 
                new HashMap<>(request.getInputs()) : new HashMap<>();
            
            // 从 inputs 中提取 files 参数（如果存在）
            Object filesFromInputs = inputs.get("files");
            if (filesFromInputs != null) {
                // 确保 files 是 List 格式
                if (filesFromInputs instanceof List) {
                    requestParams.put("files", filesFromInputs);
                    log.info("从 inputs 中提取到 files 参数: {}", JSON.toJSONString(filesFromInputs));
                } else {
                    log.warn("files 参数格式不正确，期望 List 类型，实际: {}", filesFromInputs.getClass().getName());
                }
                // 从 inputs 中移除 files，避免重复传递
                //inputs.remove("files");
            }
            
            //requestParams.put("inputs", inputs);
            requestParams.put("response_mode", request.getResponseMode() != null ? request.getResponseMode() : "streaming");
            requestParams.put("user", userId);
            
            // 如果前端单独传递了 files 参数（用于 Chatflow 文件上传），则添加到请求参数中
            if (request.getFiles() != null && !request.getFiles().isEmpty()) {
                //requestParams.put("files", request.getFiles());
                log.info("工作流包含 {} 个文件（Chatflow 文件上传）", request.getFiles().size());
            }
            
            if (request.getTraceId() != null && !request.getTraceId().trim().isEmpty()) {
                requestParams.put("trace_id", request.getTraceId());
            }
            
            String requestJson = JSON.toJSONString(requestParams);
            System.out.println("发送到 Workflow API 的请求参数:============================== "+requestJson);
            
            String requestUrl = apiBaseUrl + "/workflows/run";
            difyClientService.sendWorkflowStream(
                requestUrl,
                actualApiKey,
                requestJson,
                new WorkflowStreamResponseHandler() {
                    @Override
                    public void onTextChunk(String text, String[] fromVariableSelector) {
                        try {
                            Map<String, Object> event = new HashMap<>();
                            event.put("event", "text_chunk");
                            event.put("text", text);
                            if (fromVariableSelector != null) {
                                event.put("from_variable_selector", fromVariableSelector);
                            }
                            emitter.send(JSON.toJSONString(event));
                        } catch (Exception e) {
                            log.error("发送文本片段异常", e);
                        }
                    }
                    
                    @Override
                    public void onWorkflowStarted(String workflowRunId, String taskId, String workflowId) {
                        try {
                            Map<String, Object> event = new HashMap<>();
                            event.put("event", "workflow_started");
                            event.put("workflow_run_id", workflowRunId);
                            event.put("task_id", taskId);
                            Map<String, Object> data = new HashMap<>();
                            data.put("id", workflowRunId);
                            data.put("workflow_id", workflowId);
                            event.put("data", data);
                            emitter.send(JSON.toJSONString(event));
                        } catch (Exception e) {
                            log.error("发送工作流开始事件异常", e);
                        }
                    }
                    
                    @Override
                    public void onNodeStarted(String nodeId, String nodeType, String title, int index) {
                        try {
                            Map<String, Object> event = new HashMap<>();
                            event.put("event", "node_started");
                            Map<String, Object> data = new HashMap<>();
                            data.put("node_id", nodeId);
                            data.put("node_type", nodeType);
                            data.put("title", title);
                            data.put("index", index);
                            event.put("data", data);
                            emitter.send(JSON.toJSONString(event));
                        } catch (Exception e) {
                            log.error("发送节点开始事件异常", e);
                        }
                    }
                    
                    @Override
                    public void onNodeFinished(String nodeId, String status, Object outputs) {
                        try {
                            Map<String, Object> event = new HashMap<>();
                            event.put("event", "node_finished");
                            Map<String, Object> data = new HashMap<>();
                            data.put("node_id", nodeId);
                            data.put("status", status);
                            if (outputs != null) {
                                data.put("outputs", outputs);
                            }
                            event.put("data", data);
                            emitter.send(JSON.toJSONString(event));
                        } catch (Exception e) {
                            log.error("发送节点完成事件异常", e);
                        }
                    }
                    
                    @Override
                    public void onWorkflowFinished(String workflowRunId, String status, Object outputs) {
                        try {
                            Map<String, Object> event = new HashMap<>();
                            event.put("event", "workflow_finished");
                            event.put("workflow_run_id", workflowRunId);
                            Map<String, Object> data = new HashMap<>();
                            data.put("id", workflowRunId);
                            data.put("status", status);
                            if (outputs != null) {
                                data.put("outputs", outputs);
                            }
                            event.put("data", data);
                            emitter.send(JSON.toJSONString(event));
                        } catch (Exception e) {
                            log.error("发送工作流完成事件异常", e);
                        }
                    }
                    
                    @Override
                    public void onTtsMessage(String messageId, String audio) {
                        try {
                            Map<String, Object> event = new HashMap<>();
                            event.put("event", "tts_message");
                            event.put("message_id", messageId);
                            event.put("audio", audio);
                            emitter.send(JSON.toJSONString(event));
                        } catch (Exception e) {
                            log.error("发送TTS消息异常", e);
                        }
                    }
                    
                    @Override
                    public void onTtsMessageEnd(String messageId) {
                        try {
                            Map<String, Object> event = new HashMap<>();
                            event.put("event", "tts_message_end");
                            event.put("message_id", messageId);
                            emitter.send(JSON.toJSONString(event));
                        } catch (Exception e) {
                            log.error("发送TTS消息结束异常", e);
                        }
                    }
                    
                    @Override
                    public void onError(Exception error) {
                        try {
                            emitter.send("{\"error\":\"" + error.getMessage().replace("\"", "\\\"") + "\"}");
                            emitter.completeWithError(error);
                        } catch (Exception e) {
                            log.error("发送错误消息异常", e);
                        }
                    }
                    
                    @Override
                    public void onComplete() {
                        try {
                            emitter.send("[DONE]");
                            emitter.complete();
                        } catch (Exception e) {
                            log.error("完成流式响应异常", e);
                        }
                    }
                });
        } catch (Exception e) {
            log.error("Workflow 流式响应异常", e);
            try {
                // 发送错误事件，格式与 Dify API 错误格式一致
                Map<String, Object> errorEvent = new HashMap<>();
                errorEvent.put("event", "error");
                errorEvent.put("message", e.getMessage() != null ? e.getMessage() : "服务器内部错误");
                emitter.send(JSON.toJSONString(errorEvent));
            } catch (Exception ex) {
                log.error("发送错误响应异常", ex);
            } finally {
                try {
                    emitter.complete();
                } catch (Exception ex) {
                    log.error("完成 emitter 异常", ex);
                }
            }
        }
        
        return emitter;
    }
    
    /**
     * 执行指定版本 Workflow（流式响应）
     */
    @PostMapping(value = "/workflow/{workflowId}/run", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ApiOperation("执行指定版本 Workflow（流式响应）")
    public SseEmitter runWorkflowByIdStream(@PathVariable String workflowId, @RequestBody WorkflowRunRequest request) {
        final SseEmitter emitter = new SseEmitter(3600000L);
        log.info("收到指定版本 Workflow 执行请求，workflowId: {}", workflowId);
        
        try {
            // 验证 workflowId 格式
            if (!isValidUUID(workflowId)) {
                emitter.send("{\"error\":\"工作流ID格式不正确，必须是UUID格式\"}");
                emitter.complete();
                return emitter;
            }
            
            String userId = userService.getCurrentUserId();
            
            // 处理 App名称
            String actualApiKey = difyApiKey;
            if (request.getAppName() != null && !request.getAppName().trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(request.getAppName().trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                } else {
                    emitter.send("{\"error\":\"App名称 '" + request.getAppName() + "' 不存在或已禁用\"}");
                    emitter.complete();
                    return emitter;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String appName = request.getAppName();
            String apiBaseUrl = getApiBaseUrl(appName);
            
            // 构建请求参数
            Map<String, Object> requestParams = new HashMap<>();
            requestParams.put("inputs", request.getInputs() != null ? request.getInputs() : new HashMap<>());
            requestParams.put("response_mode", request.getResponseMode() != null ? request.getResponseMode() : "streaming");
            requestParams.put("user", userId);
            
            if (request.getFiles() != null && !request.getFiles().isEmpty()) {
                requestParams.put("files", request.getFiles());
            }
            
            if (request.getTraceId() != null && !request.getTraceId().trim().isEmpty()) {
                requestParams.put("trace_id", request.getTraceId());
            }
            
            String requestJson = JSON.toJSONString(requestParams);
            String requestUrl = apiBaseUrl + "/workflows/" + workflowId + "/run";
            
            // 复用相同的处理器逻辑
            difyClientService.sendWorkflowStream(requestUrl, actualApiKey, requestJson, 
                createWorkflowStreamHandler(emitter));
        } catch (Exception e) {
            log.error("指定版本 Workflow 流式响应异常", e);
            try {
                emitter.send("{\"error\":\"服务器内部错误\"}");
            } catch (Exception ex) {
                log.error("发送错误响应异常", ex);
            } finally {
                emitter.completeWithError(e);
            }
        }
        
        return emitter;
    }
    
    /**
     * 获取 Workflow 执行情况
     */
    @GetMapping("/workflow/run/{workflowRunId}")
    @ApiOperation("获取 Workflow 执行情况")
    public Map<String, Object> getWorkflowRun(@PathVariable String workflowRunId,
                                               @RequestParam(required = false) String appName) {
        try {
            // 处理 App名称
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            String url = apiBaseUrl + "/workflows/run/" + workflowRunId;
            okhttp3.Request request = new okhttp3.Request.Builder()
                    .url(url)
                    .get()
                    .addHeader("Authorization", "Bearer " + actualApiKey)
                    .addHeader("Content-Type", "application/json")
                    .build();
            
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(20, java.util.concurrent.TimeUnit.SECONDS)
                    .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            try (okhttp3.Response response = client.newCall(request).execute()) {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    JSONObject jsonResponse = JSON.parseObject(responseBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", true);
                    result.put("data", jsonResponse);
                    return result;
                } else {
                    String errorBody = response.body() != null ? response.body().string() : "Unknown error";
                    log.error("获取 Workflow 执行情况失败，状态码: {}, 错误信息: {}", response.code(), errorBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "获取 Workflow 执行情况失败: " + errorBody);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("获取 Workflow 执行情况失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 停止 Workflow 任务
     */
    @PostMapping("/workflow/tasks/{taskId}/stop")
    @ApiOperation("停止 Workflow 任务")
    public Map<String, Object> stopWorkflowTask(@PathVariable String taskId,
                                                 @RequestParam(required = false) String appName) {
        try {
            String actualUserId = userService.getCurrentUserId();
            
            // 处理 App名称
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            String url = apiBaseUrl + "/workflows/tasks/" + taskId + "/stop";
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("user", actualUserId);
            
            okhttp3.RequestBody body = okhttp3.RequestBody.create(
                JSON.toJSONString(requestBody),
                okhttp3.MediaType.get("application/json; charset=utf-8"));
            
            okhttp3.Request request = new okhttp3.Request.Builder()
                    .url(url)
                    .post(body)
                    .addHeader("Authorization", "Bearer " + actualApiKey)
                    .addHeader("Content-Type", "application/json")
                    .build();
            
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(20, java.util.concurrent.TimeUnit.SECONDS)
                    .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            try (okhttp3.Response response = client.newCall(request).execute()) {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    JSONObject jsonResponse = JSON.parseObject(responseBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", true);
                    result.put("data", jsonResponse);
                    return result;
                } else {
                    String errorBody = response.body() != null ? response.body().string() : "Unknown error";
                    log.error("停止 Workflow 任务失败，状态码: {}, 错误信息: {}", response.code(), errorBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "停止 Workflow 任务失败: " + errorBody);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("停止 Workflow 任务失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取 Workflow 日志
     */
    @GetMapping("/workflow/logs")
    @ApiOperation("获取 Workflow 日志")
    public Map<String, Object> getWorkflowLogs(
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) String status,
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "20") Integer limit,
            @RequestParam(required = false) String createdByEndUserSessionId,
            @RequestParam(required = false) String createdByAccount,
            @RequestParam(required = false) String appName) {
        try {
            // 处理 App名称
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            // 构建查询参数
            okhttp3.HttpUrl.Builder urlBuilder = okhttp3.HttpUrl.parse(apiBaseUrl + "/workflows/logs").newBuilder();
            if (keyword != null && !keyword.trim().isEmpty()) {
                urlBuilder.addQueryParameter("keyword", keyword);
            }
            if (status != null && !status.trim().isEmpty()) {
                urlBuilder.addQueryParameter("status", status);
            }
            urlBuilder.addQueryParameter("page", String.valueOf(page));
            urlBuilder.addQueryParameter("limit", String.valueOf(limit));
            if (createdByEndUserSessionId != null && !createdByEndUserSessionId.trim().isEmpty()) {
                urlBuilder.addQueryParameter("created_by_end_user_session_id", createdByEndUserSessionId);
            }
            if (createdByAccount != null && !createdByAccount.trim().isEmpty()) {
                urlBuilder.addQueryParameter("created_by_account", createdByAccount);
            }
            
            okhttp3.Request request = new okhttp3.Request.Builder()
                    .url(urlBuilder.build())
                    .get()
                    .addHeader("Authorization", "Bearer " + actualApiKey)
                    .addHeader("Content-Type", "application/json")
                    .build();
            
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(20, java.util.concurrent.TimeUnit.SECONDS)
                    .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            try (okhttp3.Response response = client.newCall(request).execute()) {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    JSONObject jsonResponse = JSON.parseObject(responseBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", true);
                    result.put("data", jsonResponse);
                    return result;
                } else {
                    String errorBody = response.body() != null ? response.body().string() : "Unknown error";
                    log.error("获取 Workflow 日志失败，状态码: {}, 错误信息: {}", response.code(), errorBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "获取 Workflow 日志失败: " + errorBody);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("获取 Workflow 日志失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取应用基本信息
     */
    @GetMapping("/workflow/info")
    @ApiOperation("获取应用基本信息")
    public Map<String, Object> getWorkflowInfo(@RequestParam(required = false) String appName) {
        try {
            // 处理 App名称
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            String url = apiBaseUrl + "/info";
            okhttp3.Request request = new okhttp3.Request.Builder()
                    .url(url)
                    .get()
                    .addHeader("Authorization", "Bearer " + actualApiKey)
                    .addHeader("Content-Type", "application/json")
                    .build();
            
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(20, java.util.concurrent.TimeUnit.SECONDS)
                    .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            try (okhttp3.Response response = client.newCall(request).execute()) {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    JSONObject jsonResponse = JSON.parseObject(responseBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", true);
                    result.put("data", jsonResponse);
                    return result;
                } else {
                    String errorBody = response.body() != null ? response.body().string() : "Unknown error";
                    log.error("获取应用基本信息失败，状态码: {}, 错误信息: {}", response.code(), errorBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "获取应用基本信息失败: " + errorBody);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("获取应用基本信息失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 获取应用 WebApp 设置
     */
    @GetMapping("/workflow/site")
    @ApiOperation("获取应用 WebApp 设置")
    public Map<String, Object> getWorkflowSite(@RequestParam(required = false) String appName) {
        try {
            // 处理 App名称
            String actualApiKey = difyApiKey;
            if (appName != null && !appName.trim().isEmpty()) {
                AppMapping mapping = appMappingService.getByAppName(appName.trim());
                if (mapping != null) {
                    actualApiKey = mapping.getRealApiKey();
                } else {
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "App名称 '" + appName + "' 不存在或已禁用");
                    return result;
                }
            }
            
            // 获取API基础URL（根据appName判断）
            String apiBaseUrl = getApiBaseUrl(appName);
            
            String url = apiBaseUrl + "/site";
            okhttp3.Request request = new okhttp3.Request.Builder()
                    .url(url)
                    .get()
                    .addHeader("Authorization", "Bearer " + actualApiKey)
                    .addHeader("Content-Type", "application/json")
                    .build();
            
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(20, java.util.concurrent.TimeUnit.SECONDS)
                    .writeTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            try (okhttp3.Response response = client.newCall(request).execute()) {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    JSONObject jsonResponse = JSON.parseObject(responseBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", true);
                    result.put("data", jsonResponse);
                    return result;
                } else {
                    String errorBody = response.body() != null ? response.body().string() : "Unknown error";
                    log.error("获取应用 WebApp 设置失败，状态码: {}, 错误信息: {}", response.code(), errorBody);
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", false);
                    result.put("error", "获取应用 WebApp 设置失败: " + errorBody);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("获取应用 WebApp 设置失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    /**
     * 创建 Workflow 流式响应处理器（辅助方法）
     */
    private WorkflowStreamResponseHandler createWorkflowStreamHandler(SseEmitter emitter) {
        return new WorkflowStreamResponseHandler() {
            @Override
            public void onTextChunk(String text, String[] fromVariableSelector) {
                try {
                    Map<String, Object> event = new HashMap<>();
                    event.put("event", "text_chunk");
                    event.put("text", text);
                    if (fromVariableSelector != null) {
                        event.put("from_variable_selector", fromVariableSelector);
                    }
                    emitter.send(JSON.toJSONString(event));
                } catch (Exception e) {
                    log.error("发送文本片段异常", e);
                }
            }
            
            @Override
            public void onWorkflowStarted(String workflowRunId, String taskId, String workflowId) {
                try {
                    Map<String, Object> event = new HashMap<>();
                    event.put("event", "workflow_started");
                    event.put("workflow_run_id", workflowRunId);
                    event.put("task_id", taskId);
                    Map<String, Object> data = new HashMap<>();
                    data.put("id", workflowRunId);
                    data.put("workflow_id", workflowId);
                    event.put("data", data);
                    emitter.send(JSON.toJSONString(event));
                } catch (Exception e) {
                    log.error("发送工作流开始事件异常", e);
                }
            }
            
            @Override
            public void onNodeStarted(String nodeId, String nodeType, String title, int index) {
                try {
                    Map<String, Object> event = new HashMap<>();
                    event.put("event", "node_started");
                    Map<String, Object> data = new HashMap<>();
                    data.put("node_id", nodeId);
                    data.put("node_type", nodeType);
                    data.put("title", title);
                    data.put("index", index);
                    event.put("data", data);
                    emitter.send(JSON.toJSONString(event));
                } catch (Exception e) {
                    log.error("发送节点开始事件异常", e);
                }
            }
            
            @Override
            public void onNodeFinished(String nodeId, String status, Object outputs) {
                try {
                    Map<String, Object> event = new HashMap<>();
                    event.put("event", "node_finished");
                    Map<String, Object> data = new HashMap<>();
                    data.put("node_id", nodeId);
                    data.put("status", status);
                    if (outputs != null) {
                        data.put("outputs", outputs);
                    }
                    event.put("data", data);
                    emitter.send(JSON.toJSONString(event));
                } catch (Exception e) {
                    log.error("发送节点完成事件异常", e);
                }
            }
            
            @Override
            public void onWorkflowFinished(String workflowRunId, String status, Object outputs) {
                try {
                    Map<String, Object> event = new HashMap<>();
                    event.put("event", "workflow_finished");
                    event.put("workflow_run_id", workflowRunId);
                    Map<String, Object> data = new HashMap<>();
                    data.put("id", workflowRunId);
                    data.put("status", status);
                    if (outputs != null) {
                        data.put("outputs", outputs);
                    }
                    event.put("data", data);
                    emitter.send(JSON.toJSONString(event));
                } catch (Exception e) {
                    log.error("发送工作流完成事件异常", e);
                }
            }
            
            @Override
            public void onTtsMessage(String messageId, String audio) {
                try {
                    Map<String, Object> event = new HashMap<>();
                    event.put("event", "tts_message");
                    event.put("message_id", messageId);
                    event.put("audio", audio);
                    emitter.send(JSON.toJSONString(event));
                } catch (Exception e) {
                    log.error("发送TTS消息异常", e);
                }
            }
            
            @Override
            public void onTtsMessageEnd(String messageId) {
                try {
                    Map<String, Object> event = new HashMap<>();
                    event.put("event", "tts_message_end");
                    event.put("message_id", messageId);
                    emitter.send(JSON.toJSONString(event));
                } catch (Exception e) {
                    log.error("发送TTS消息结束异常", e);
                }
            }
            
            @Override
            public void onError(Exception error) {
                try {
                    emitter.send("{\"error\":\"" + error.getMessage().replace("\"", "\\\"") + "\"}");
                    emitter.completeWithError(error);
                } catch (Exception e) {
                    log.error("发送错误消息异常", e);
                }
            }
            
            @Override
            public void onComplete() {
                try {
                    emitter.send("[DONE]");
                    emitter.complete();
                } catch (Exception e) {
                    log.error("完成流式响应异常", e);
                }
            }
        };
    }
    
    /**
     * 文件代理接口 - 将 Dify 内部文件 URL 代理到前端
     * 支持签名过期时自动重新获取
     */
    @GetMapping("/files/proxy/**")
    @ApiOperation("文件代理接口")
    public void proxyDifyFile(javax.servlet.http.HttpServletRequest request,
                               javax.servlet.http.HttpServletResponse response) {
        try {
            // 获取完整的请求路径（不包含查询参数）
            String fullPath = request.getRequestURI();
            // 提取 /files/proxy/ 之后的路径
            String filePath = fullPath.substring(fullPath.indexOf("/files/proxy/") + "/files/proxy/".length());
            
            // 获取查询参数（包含 timestamp、nonce、sign 等）
            String queryString = request.getQueryString();
            if (queryString != null && !queryString.isEmpty()) {
                filePath = filePath + "?" + queryString;
            }
            
            log.info("代理文件请求: {}", filePath);
            
            // 提取文件ID（用于重新获取）
            String fileId = extractFileIdFromPath(filePath);
            
            // 构建 Dify 文件 URL（包含完整的查询参数）
            String difyFileUrl = DIFY_API_BASE_URL.replace("/v1", "") + "/files/" + filePath;
            log.info("目标 Dify 文件 URL: {}", difyFileUrl);
            
            // 创建 OkHttpClient
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(60, java.util.concurrent.TimeUnit.SECONDS)
                    .writeTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            // 第一次尝试：使用原始 URL（可能包含旧签名）
            okhttp3.Request difyRequest = new okhttp3.Request.Builder()
                    .url(difyFileUrl)
                    .get()
                    .build();
            
            // 执行请求
            try (okhttp3.Response difyResponse = client.newCall(difyRequest).execute()) {
                // 如果返回 403，说明签名过期，尝试重新获取
                if (difyResponse.code() == 403 && fileId != null) {
                    log.warn("文件签名过期，尝试重新获取: {}", fileId);
                    String newSignedUrl = fetchNewFileUrl(fileId);
                    
                    if (newSignedUrl != null) {
                        log.info("成功获取新的签名 URL: {}", newSignedUrl);
                        // 第二次尝试：使用新的签名 URL
                        okhttp3.Request retryRequest = new okhttp3.Request.Builder()
                                .url(newSignedUrl)
                                .get()
                                .build();
                        
                        try (okhttp3.Response retryResponse = client.newCall(retryRequest).execute()) {
                            if (retryResponse.isSuccessful() && retryResponse.body() != null) {
                                serveFileResponse(retryResponse, response, filePath);
                                return;
                            }
                        }
                    }
                    
                    // 如果重新获取也失败，返回错误
                    log.error("重新获取文件失败: {}", fileId);
                    response.setStatus(403);
                    response.getWriter().write("File signature expired and failed to refresh");
                    return;
                }
                
                // 正常返回（签名仍然有效）
                if (difyResponse.isSuccessful() && difyResponse.body() != null) {
                    serveFileResponse(difyResponse, response, filePath);
                } else {
                    String errorBody = difyResponse.body() != null ? difyResponse.body().string() : "Unknown error";
                    log.error("从 Dify 获取文件失败，状态码: {}, 错误信息: {}", difyResponse.code(), errorBody);
                    response.setStatus(difyResponse.code());
                    response.getWriter().write("Failed to fetch file from Dify: " + errorBody);
                }
            }
        } catch (Exception e) {
            log.error("文件代理失败", e);
            try {
                response.setStatus(500);
                response.getWriter().write("Internal server error: " + e.getMessage());
            } catch (Exception ex) {
                log.error("发送错误响应失败", ex);
            }
        }
    }
    
    /**
     * 从文件路径中提取文件ID
     * @param filePath 如: tools/1dd518a6-b03e-4939-87d6-abc715939401.docx?timestamp=...
     * @return 文件ID: 1dd518a6-b03e-4939-87d6-abc715939401
     */
    private String extractFileIdFromPath(String filePath) {
        try {
            // 去除查询参数
            String pathOnly = filePath.split("\\?")[0];
            
            // 提取文件名: 1dd518a6-b03e-4939-87d6-abc715939401.docx
            String fileName = pathOnly.substring(pathOnly.lastIndexOf('/') + 1);
            
            // 去除扩展名: 1dd518a6-b03e-4939-87d6-abc715939401
            int dotIndex = fileName.lastIndexOf('.');
            return dotIndex > 0 ? fileName.substring(0, dotIndex) : fileName;
        } catch (Exception e) {
            log.warn("提取文件ID失败: {}", filePath, e);
            return null;
        }
    }
    
    /**
     * 通过 Dify API 重新获取文件的签名 URL
     * @param fileId 文件ID (upload_file_id)
     * @return 新的带签名的 URL，失败返回 null
     */
    private String fetchNewFileUrl(String fileId) {
        try {
            // 方案1：通过 Files API 获取（如果 Dify 提供）
            // GET {DIFY_API_BASE_URL}/files/{fileId}
            String filesApiUrl = DIFY_API_BASE_URL + "/files/" + fileId;
            
            okhttp3.Request request = new okhttp3.Request.Builder()
                    .url(filesApiUrl)
                    .header("Authorization", "Bearer " + difyApiKey)
                    .header("Content-Type", "application/json")
                    .get()
                    .build();
            
            okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                    .connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .readTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .build();
            
            try (okhttp3.Response response = client.newCall(request).execute()) {
                if (response.isSuccessful() && response.body() != null) {
                    String responseBody = response.body().string();
                    log.info("Files API 响应: {}", responseBody);
                    
                    com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSON.parseObject(responseBody);
                    
                    // 尝试从不同字段获取 URL
                    String newUrl = json.getString("url");
                    if (newUrl == null) {
                        newUrl = json.getString("download_url");
                    }
                    if (newUrl == null && json.containsKey("data")) {
                        com.alibaba.fastjson.JSONObject data = json.getJSONObject("data");
                        newUrl = data.getString("url");
                    }
                    
                    if (newUrl != null) {
                        log.info("成功通过 Files API 获取新 URL");
                        return newUrl;
                    }
                }
                log.warn("Files API 未返回有效 URL，状态码: {}", response.code());
            }
            
            // 方案2：如果方案1失败，返回null（可以扩展其他方案）
            // 例如：通过 Conversation API 重新获取消息中的文件
            log.warn("无法通过 API 重新获取文件 URL: {}", fileId);
            return null;
            
        } catch (Exception e) {
            log.error("重新获取文件 URL 失败: {}", fileId, e);
            return null;
        }
    }
    
    /**
     * 将 Dify 响应的文件内容返回给前端
     */
    private void serveFileResponse(okhttp3.Response difyResponse, 
                                   javax.servlet.http.HttpServletResponse response,
                                   String filePath) throws Exception {
        // 设置响应头
        String contentType = difyResponse.header("Content-Type");
        if (contentType != null) {
            response.setContentType(contentType);
        }
        
        String contentDisposition = difyResponse.header("Content-Disposition");
        if (contentDisposition != null) {
            response.setHeader("Content-Disposition", contentDisposition);
        }
        
        Long contentLength = difyResponse.body().contentLength();
        if (contentLength != null && contentLength > 0) {
            response.setContentLengthLong(contentLength);
        }
        
        // 复制响应体
        java.io.InputStream inputStream = difyResponse.body().byteStream();
        java.io.OutputStream outputStream = response.getOutputStream();
        
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        
        outputStream.flush();
        log.info("文件代理成功: {}", filePath);
    }
}
